package util;

import java.io.*;

/**
 * This is a class of {@link File} utility functions.
 *
 * @author Neil Dickson
 */
public final class FileUtil {
	/**
	 * This reads the content of a file.
	 *
	 * @param filename the name of the file to read
	 * @return the content of the file with the specified filename
	 * @throws IOException when opening/reading the file doesn't work
	 */
	public static byte[] readFile(String filename) throws IOException {
		return readFile(new File(filename));
	}
	/**
	 * This reads the content of a file.
	 *
	 * @param file the file to read
	 * @return the content of the file
	 * @throws IOException when opening/reading the file doesn't work
	 */
	public static byte[] readFile(File file) throws IOException {
		long length = file.length();
		// NOTE: Limit of 2GB (exclusive) because length must be cast to an int
		if (length>=0x80000000L) {
			throw new OutOfMemoryError("Wow! You're trying to read in a whole file that's "+(length/1048576)+"MB large!");
		}
		byte[] content = new byte[(int)length];
		FileInputStream input = new FileInputStream(file);
		input.read(content);
		input.close();
		return content;
	}
	/**
	 * This reads the text contained in a file.
	 *
	 * @param filename the name of the file to read
	 * @return the text contained in the file with the specified filename
	 * @throws IOException when opening/reading the file doesn't work
	 */
	public static String readFileString(String filename) throws IOException {
		return readFileToString(new File(filename));
	}
	/**
	 * This reads the text contained in a file.
	 *
	 * @param file the file to read
	 * @return the text contained in the file with the specified filename
	 * @throws IOException when opening/reading the file doesn't work
	 */
	public static String readFileToString(File file) throws IOException {
		String string = new String(readFile(file));
		// Garbage collect if 512KB or larger
		if (string.length()>=0x80000){
			System.gc();
		}
		return string;
	}
	/**
	 * This reads the text contained in a {@link Reader}.
	 *
	 * @param reader the {@link Reader} from which to read
	 * @return the text contained in the {@link Reader}
	 * @throws IOException when opening/reading the file doesn't work
	 */
	public static String readFileString(Reader reader) throws IOException {
		BufferedReader input = new BufferedReader(reader);
		StringBuffer buf = new StringBuffer();
		String line;
		while ((line = input.readLine())!=null) {
			buf.append(line).append("\n");
		}
		input.close();
		return buf.toString();
	}

	/**
	 * This checks for any characters not allowed in filenames.
	 *
	 * @param name the filename to check (without a path)
	 * @return null if the filename is fine, else the name with invalid characters removed
	 */
	public static String removeBadFilenameChars(String name) {
		String notAllowed = "\\/:*?\"<>|";
		boolean changed = false;
		for (int i=0;i<notAllowed.length();++i) {
			int index;
			while ((index = name.indexOf(notAllowed.charAt(i)))>=0) {
				name = name.substring(0,index)+name.substring(index+1);
				changed = true;
			}
		}
		if (!changed) {
			return null;
		}
		return name;
	}

	/**
	 * This copies the source file to the destination file.
	 *
	 * @param source the source file path
	 * @param destination the destination file path
	 * @throws IOException if the file operations don't work
	 */
	public static void copyFile(String source,String destination) throws IOException {
		File sourceFile = new File(source);
		if (sourceFile.isFile()) {
			long length = sourceFile.length();
			File destFile = new File(destination);
			if (!destFile.exists()) {
				destFile.createNewFile();
			}
			else {
				destFile.delete();
				destFile.createNewFile();
			}
			BufferedInputStream input = new BufferedInputStream(new FileInputStream(sourceFile));
			BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(destFile));
			byte[] buffer = new byte[16384];
			for (int i=0;i<length;i+=buffer.length) {
				int amountRead = input.read(buffer,0,(int)Math.min(length-i,buffer.length));
				output.write(buffer,0,amountRead);
			}
			input.close();
			output.close();
		}
	}

	public static void writeLong(OutputStream output,long i) throws IOException {
		output.write((int)(i&0xFF));
		output.write((int)((i>>>8)&0xFF));
		output.write((int)((i>>>16)&0xFF));
		output.write((int)((i>>>24)&0xFF));
		output.write((int)((i>>>32)&0xFF));
		output.write((int)((i>>>40)&0xFF));
		output.write((int)((i>>>48)&0xFF));
		output.write((int)(i>>>56));
	}

	public static void writeInt(OutputStream output,int i) throws IOException {
		output.write(i&0xFF);
		output.write((i>>>8)&0xFF);
		output.write((i>>>16)&0xFF);
		output.write(i>>>24);
	}

	public static void writeShort(OutputStream output,short i) throws IOException {
		output.write(i&0xFF);
		output.write(i>>>8);
	}

	public static void writeChar(OutputStream output,char i) throws IOException {
		output.write(i&0xFF);
		output.write(i>>>8);
	}

	public static void writeString8(OutputStream output,String s) throws IOException {
		output.write(s.getBytes());
	}

	public static void writeString16(OutputStream output,String s) throws IOException {
		char[] chars = s.toCharArray();
		for (char c : chars) {
			writeChar(output,c);
		}
	}
}
